//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2013 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_ITERATOR_COUNTER_H_
#define _BUOLA_ITERATOR_COUNTER_H_

#include <buola/iterator/facade.h>
#include <buola/iterator/range.h>
#include <limits>

namespace buola {

///\addtogroup iterators
///@{

///\cond
template<typename tValue>
class ICounter;
    
namespace detail {
    
    template<typename tValue>
    using OCounterFacade=IFacade<ICounter<tValue>,OConditional<QIsNumeric<tValue>,
                                GCachingRandomAccessIterator,std::forward_iterator_tag>,const tValue>;
    
/*namespace detail*/ }
///\endcond

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// counter iterator
///
/// This class allows the use of any incrementable object as an iterator. For example, it allows
/// to iterate over a series of consecutive integers. Its use is not restricted to integral
/// types. Any type that is Incrementable and EqualityComparable can be used as its base type.
///
/// \tparam tValue the underlying type
///
/// For examples, see the helper functions \ref counter_iterator and \ref counter_range
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
template<typename tValue>
class ICounter : public detail::OCounterFacade<tValue>
{
    typedef detail::OCounterFacade<tValue> TBase;
    friend TBase;

public:
    ///initializes the iterator from a `tValue`
    explicit ICounter(const tValue &pValue)
        :   mValue(pValue)
    {}
    
private:
    ///returns the current value of the counter.
    const tValue &Dereference() const
    {
        return mValue;
    }
    
    ///increments the value of the iterator
    void Increment()
    {
        ++mValue;
    }

    ///decrements the value of the iterator
    void Decrement()
    {
        --mValue;
    }

    ///returns true if the two iterators contain the same value
    bool Equal(const ICounter &pO) const
    {
        return mValue==pO.mValue;
    }

    ///advances the iterator by \p pN
    void Advance(typename TBase::difference_type pN)
    {
        mValue+=pN;
    }
    
    ///returns the distance to iterator \p pRH
    typename TBase::difference_type DistanceTo(const ICounter &pRH) const
    {
        return pRH.mValue-mValue;
    }
    
    tValue mValue;
};

///\name Counter
//@{

///returns an `ICounter` iterator object which wraps any incrementable object
///
///\param pV the initial value of the iterator
///
///Incrementing and decrementing the iterator will perform the same operation on the stored value, which
///will be returned when the iterator is dereferenced.
///
///The returned iterators can also be compared, and will be considered equal when the stored values are equal
///
///For example,
///
///~~~~~~~~~~~~~~
///std::vector<int> lVector(counter_iterator(10),counter_iterator(50));
///~~~~~~~~~~~~~~
///
///initializes a vector with the numbers from 10 to 49, inclusive.
template<typename tValue>
inline ICounter<tValue> counter_iterator(const tValue &pV)
{
    return ICounter<tValue>(pV);
}

///returns an iterator range which contains an interval of values
///
///\param pB the first value in the range
///\param pE the past-the-end value in the range (not inclusive)
///
///Iterating over the range will yield all values between \p pB and \p pE.
///
///It is equivalent to `range(counter_iterator(pB),counter_iterator(pE))`
///
///The following code
///
///~~~~~~~~~~~~~~~~
///for(int i : counter_range(0,100)) { ... }
///~~~~~~~~~~~~~~~~
///
///would be roughly equivalent to
///
///~~~~~~~~~~~~~~~~
///for(int i=0;i<100;i++) { ... }
///~~~~~~~~~~~~~~~~
///
///and probably slower!
template<typename tValue>
inline CRange<ICounter<tValue>> counter_range(const tValue &pB,const tValue &pE)
{
    return {ICounter<tValue>(pB),ICounter<tValue>(pE)};
}

//@}

///@}

/*namespace buola*/ }

#endif
